﻿using System.ComponentModel.Composition;
using System.Threading;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;
using Roslyn.Compilers.Common;
using Roslyn.Services;
using Roslyn.Services.Editor;

namespace Roslyn.Refactoring.Library
{
    [ExportCodeRefactoringProvider("Extract Parameter", LanguageNames.CSharp)]
    class CodeRefactoringProvider : ICodeRefactoringProvider
    {
        private readonly ICodeActionEditFactory _editFactory;
        private readonly IFindReferencesService _findRefs;

        [ImportingConstructor]
        public CodeRefactoringProvider(ICodeActionEditFactory editFactory)
        {
            this._editFactory = editFactory;
        }

        public CodeRefactoring GetRefactoring(IDocument document, TextSpan textSpan, CancellationToken cancellationToken)
        {
            // var semantic = document.GetSemanticModel(cancellationToken);
            var syntax = document.GetSyntaxTree(cancellationToken);
            
            var expressionToken = GetExpressionNode(textSpan, syntax);
            if (expressionToken == null)
                return null;
            var method = GetMethodNode(expressionToken);
            if (method == null)
                return null;
            return new CodeRefactoring(new []{new ExtractParameterAction(_editFactory, document, expressionToken, method)}, expressionToken.Span);
        }

        private static MethodDeclarationSyntax GetMethodNode(ExpressionSyntax expressionToken)
        {
            CommonSyntaxNode methodDeclarationToken = expressionToken.Parent;
            while (methodDeclarationToken.Kind != (int) SyntaxKind.MethodDeclaration)
            {
                methodDeclarationToken = methodDeclarationToken.Parent;
                if (methodDeclarationToken == null)
                    return null;
            }
            return (MethodDeclarationSyntax) methodDeclarationToken;
        }

        private static ExpressionSyntax GetExpressionNode(TextSpan textSpan, CommonSyntaxTree syntax)
        {
            CommonSyntaxNode expressionToken = syntax.Root.FindToken(textSpan.Start).Parent;
            while (!(expressionToken is ExpressionSyntax))
            {
                expressionToken = expressionToken.Parent;
                if (expressionToken == null)
                    return null;
            }
            return (ExpressionSyntax) expressionToken;
        }
    }
}
